package learning.spring.speaker;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;

/**
 * 该SpeakerBeanFactoryPostProcessor类会在Application类中的main方法new一个Application上下文对象后再执行
 * </p>
 * 1、根据 spring.speaker.enable 开关确定是否自动配置 speaker Bean。
 * 2、根据 spring.speaker.language 动态确定使用哪个 Speaker 接口的实现。
 * 3、将确定的 Speaker 实现注册到 Spring 上下文中。
 */
@SuppressWarnings("NullableProblems")
public class SpeakerBeanFactoryPostProcessor implements BeanFactoryPostProcessor, EnvironmentAware {

    // 为了获得配置属性，注入Environment
    private Environment environment;

    /**
     * EnvironmentAware 接口的方法 setEnvironment
     */
    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    /**
     * postProcessBeanFactory 是 BeanFactoryPostProcessor 接口的方法。
     * BeanFactoryPostProcessor接口是Spring提供的扩展点，允许在BeanFactory创建实例后，对BeanFactory进行修改。
     *
     * @param beanFactory Spring的BeanFactory
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 获取属性值
        String enable = environment.getProperty("spring.speaker.enable");
        String language = environment.getProperty("spring.speaker.language", "English");
        String clazz = "learning.spring.speaker." + language + "Speaker";

        // 开关为true则注册Bean，否则结束
        if (!"true".equalsIgnoreCase(enable)) {
            return;
        }
        // 如果目标类不存在，结束处理
        if (!org.springframework.util.ClassUtils.isPresent(clazz, SpeakerBeanFactoryPostProcessor.class.getClassLoader())) {
            return;
        }

        if (beanFactory instanceof BeanDefinitionRegistry) {
            // 如果是BeanDefinitionRegistry，可以注册BeanDefinition
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClassName(clazz);
            ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition("speaker", beanDefinition);
        } else {
            // 如果只能识别成ConfigurableListableBeanFactory，直接注册一个Bean实例
            try {
                Speaker speaker = (Speaker) ClassUtils.forName(clazz, SpeakerBeanFactoryPostProcessor.class.getClassLoader())
                        .getDeclaredConstructor().newInstance();
                beanFactory.registerSingleton("speaker", speaker);
            } catch (Exception ignored) {
            }
        }
        System.out.println("Registered " + clazz + " as speaker.");
    }

}
